package com.ayf.payment.game.api.service.payment;

import com.alibaba.fastjson.JSONObject;
import com.ayf.payment.game.api.dto.MerchantAccountOptions;
import com.ayf.payment.game.api.dto.platform.MerchantCashOutDTO;
import com.ayf.payment.game.api.dto.platform.MerchantSettleDTO;
import com.ayf.payment.game.api.dto.platform.SubstitutePayConfigDTO;
import com.ayf.payment.game.api.dto.platform.criteria.SubstitutePayCriteria;
import com.ayf.payment.game.api.service.MerchantAccountService;
import com.ayf.payment.game.api.service.platform.MerchantCashOutService;
import com.ayf.payment.game.api.service.platform.MerchantSettleService;
import com.ayf.payment.game.api.service.platform.SubstitutePayConfigService;
import com.ayf.payment.game.api.type.MerchantPayOrderStatusEnum;
import com.ayf.payment.game.api.utils.CommonResult;
import com.ayf.payment.game.api.utils.DateUtils;
import com.ayf.payment.game.api.utils.SnowFlakeUtils;
import com.swwx.charm.commons.lang.utils.LogPortal;
import com.swwx.charm.zookeeper.exception.GetLockFailedException;
import com.swwx.charm.zookeeper.exception.ReleaseLockFailedException;
import com.swwx.charm.zookeeper.lock.DistributedLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @author wwl
 * @date 2020/3/24 20:06
 */
@Service
public class EHBPaymentOnbehalfOfService {
    @Autowired
    private MerchantCashOutService merchantCashOutService;

    @Autowired
    private MerchantAccountService merchantAccountService;
    @Autowired
    private MerchantSettleService merchantSettleService;

    @Autowired
    private com.ayf.payment.game.api.channel.ChannelHandleFactory channelHandleFactory;
    @Autowired
    private SubstitutePayConfigService substitutePayConfigService;

    @Autowired
    protected DistributedLock distributedLock;

    public CommonResult paymentOnbehalfOf(String operatorName, MerchantCashOutDTO merchantCashOut, String payChannelCode, String tradePwd) {
        CommonResult commonResult = new CommonResult();
        commonResult.setCode(200);
        commonResult.setMsg("代付下单成功");
        String traceId = SnowFlakeUtils.getTraceId();

        if (merchantCashOut.getTradeStatus() == 2 || merchantCashOut.getTradeStatus() == 0) {
            // 查询代付通道接口
            SubstitutePayConfigDTO substitutePayConfigDTO = null;

            SubstitutePayCriteria substitutePayCriteria = new SubstitutePayCriteria();
            substitutePayCriteria.setChannelType(merchantCashOut.getSettleType());
            substitutePayCriteria.setChannelStatus(1);
            substitutePayCriteria.setChannelCode(payChannelCode);
            List<SubstitutePayConfigDTO> list = substitutePayConfigService.getListSubstitutePayConfigByChannelCode(substitutePayCriteria);
            String failMsg = "";
            if (CollectionUtils.isEmpty(list)) {
                commonResult.setCode(-1);
                commonResult.setMsg("代付提交失败，没有可用代付通道，错误码:" + traceId);
                return commonResult;
            }
            String finalStatus = "YH_ERROR";
            JSONObject balanceParam = new JSONObject();
            // 商户系统内部订单号，要求64个字符内，只能是数字、大小写字母_-|* 且在同一个商户号下唯一
            balanceParam.put("traceId", traceId);
            balanceParam.put("bankName", merchantCashOut.getBankName());
            for (SubstitutePayConfigDTO dto : list) {
                balanceParam.put("substitutePayConfigId", dto.getId());
                JSONObject balanceQuery = channelHandleFactory.getHandler(dto.getChannelCode()).balanceQuery(balanceParam);
                Integer status = balanceQuery.getInteger("status");
                if (status == 1) {
                    finalStatus = "YE_ERROR";
                    BigDecimal balance = balanceQuery.getBigDecimal("balance");
                    if (balance.compareTo(merchantCashOut.getActualAmount()) > -1) {
                        substitutePayConfigDTO = dto;
                        break;
                    }
                }
            }
            if (finalStatus.equals("YH_ERROR")) {
                failMsg = "银行类型错误，暂不支持此银行代付";
            } else {
                failMsg = "代付账户余额不足";
            }

            if (substitutePayConfigDTO != null) {
                // 调用通道发起代付
                JSONObject inputParam = new JSONObject();
                // 商户系统内部订单号，要求64个字符内，只能是数字、大小写字母_-|* 且在同一个商户号下唯一
                inputParam.put("merchant_order_no", merchantCashOut.getTradeNumber());
                // 订单总金额，单位为元
                inputParam.put("amount", merchantCashOut.getActualAmount());
                // 原账号数值 银行卡号或者支付宝账号
                // 必须进行AES加密，此数值是银行卡号或者支付宝账号
                inputParam.put("account_no", merchantCashOut.getCardNo());
                // 账号名称 此数值是银行卡号或者支付宝账号对应的户名
                inputParam.put("account_name", merchantCashOut.getAccountName());

                // 交易描述，要求300个字符内，不能包含特殊字符:英文逗号，注意：下载对账单会返回此字段数据
                inputParam.put("description", "");
                // 交易发起时间时间，格式为yyyyMMddHHmmss
                inputParam.put("apply_time", DateUtils.dateToIntegerst(new Date(), DateUtils.formatPattern_full_01));
                // 付款类型 0-银行卡 1-支付宝 2-爱游宝
                inputParam.put("account_type",merchantCashOut.getSettleType());
                // 银行名称
                inputParam.put("bank_name", merchantCashOut.getBankName());

                inputParam.put("bank_city", merchantCashOut.getBankCity());
                inputParam.put("bank_province", merchantCashOut.getBankProvince());
                inputParam.put("bank_branch_bame",merchantCashOut.getBankBranchName());
                inputParam.put("bank_branch_no",merchantCashOut.getBankBranchNo());

                inputParam.put("channelCode", substitutePayConfigDTO.getChannelCode());
                inputParam.put("substitutePayConfigId", substitutePayConfigDTO.getId());
                inputParam.put("traceId", traceId);
                inputParam.put("tradePwd",tradePwd);
                JSONObject channelResResult;
                try {
                    merchantCashOut.setPayChannelId(substitutePayConfigDTO.getId());
                    merchantCashOut.setPayChannelCode(substitutePayConfigDTO.getChannelCode());
                    merchantCashOutService.updateMerchantCashOut(merchantCashOut);
                    channelResResult = channelHandleFactory.getHandler(inputParam.getString("channelCode")).orderCreate(inputParam);
                    if (channelResResult == null) {
                        commonResult.setCode(-1);
                        commonResult.setMsg("代付提交失败，请联系技术支持，错误码:" + traceId);
                        return commonResult;
                    }
                    Integer status = channelResResult.getInteger("status");
                    String failReason = channelResResult.getString("failReason");
                    if (MerchantPayOrderStatusEnum.PAY_FAIL.getStatus().equals(status)) {
                        commonResult.setCode(-11);
                        commonResult.setMsg("代付提交失败，原因:" + failReason + "，错误码:" + traceId);

                        merchantCashOut.setTradeStatus((short) 4);
                        merchantCashOut.setOperatorName(operatorName);
                        merchantCashOut.setOperatorTime(new Date());
                        merchantCashOut.setPayChannelId(substitutePayConfigDTO.getId());
                        merchantCashOut.setPayChannelCode(substitutePayConfigDTO.getChannelCode());
                        merchantCashOut.setReturnMsg(failReason);
                        merchantCashOut.setChannelOrderNo(channelResResult.getString("channelOrderNo"));
                        merchantCashOutService.updateMerchantCashOut(merchantCashOut);

                        boolean lock = false;
                        String lockName = System.getenv("XY_GAME_PAY_LOCK_FLAG").concat(merchantCashOut.getTradeNumber()).concat("agentPay");
                        try {
                            if (lock = distributedLock.getLock(lockName)) {
                                if (merchantCashOut.getIsAtuoSettle() == 0) {  //结算
                                    MerchantSettleDTO merchantSettleDTO = merchantSettleService.getMerchantSettleBySettleOrderNo(merchantCashOut.getSettleOrderOn());
                                    Integer settleStatus = Integer.valueOf(2);
                                    //已结算总金额
                                    BigDecimal settledAmt = merchantSettleDTO.getSettledAmt()==null?BigDecimal.ZERO:merchantSettleDTO.getSettledAmt();
                                    if (settledAmt.compareTo(merchantCashOut.getAmount())==0){
                                        settleStatus = Integer.valueOf(0);
                                    }
                                    merchantSettleService.updateSettleAmtAndSettleStatusBySettleOrderNo(merchantCashOut.getSettleOrderOn(),merchantCashOut.getAmount().negate(), settleStatus);
                                } else if (merchantCashOut.getIsAtuoSettle() ==2) { // 实时结算申请
                                    MerchantAccountOptions merchantAccountOptions = new MerchantAccountOptions();
                                    merchantAccountOptions.setOptionType("实时结算失败");
                                    merchantAccountOptions.setOptionCash(merchantCashOut.getAmount());
                                    merchantAccountOptions.setFreezing(merchantCashOut.getAmount().negate());
                                    merchantAccountOptions.setMerchantId(merchantCashOut.getMerchantId());
                                    merchantAccountService.updateMerchantAccount(merchantAccountOptions);
                                }else{ //GM可提现金额提现
                                    MerchantAccountOptions merchantAccountOptions = new MerchantAccountOptions();
                                    merchantAccountOptions.setOptionType("提现失败");
                                    merchantAccountOptions.setCashWithdrawal(merchantCashOut.getAmount());
                                    merchantAccountOptions.setCashWithdrawalIng(merchantCashOut.getAmount().negate());
                                    merchantAccountOptions.setMerchantId(merchantCashOut.getMerchantId());
                                    merchantAccountService.updateMerchantAccount(merchantAccountOptions);
                                }
                            }
                        } catch (GetLockFailedException e) {
                            LogPortal.error("{} >>> {} 获取lock失败", e, traceId, lockName);
                        } catch (Exception e) {
                            LogPortal.error("{} >>> {} 任务执行出错 ", e, traceId, lockName);
                        } finally {
                            if (lock) {
                                LogPortal.info(traceId + " >>> " + lockName + " finished.");
                                try {
                                    distributedLock.releaseLock(lockName);
                                } catch (ReleaseLockFailedException e) {
                                    LogPortal.error("{} >>> {} 释放失败", e, traceId, lockName);
                                }
                            }
                        }
                    } else if (MerchantPayOrderStatusEnum.PAY_PROCESSING.getStatus().equals(status)) {
                        merchantCashOut.setTradeStatus((short) 5);
                        merchantCashOut.setOperatorName(operatorName);
                        merchantCashOut.setOperatorTime(new Date());
                        merchantCashOut.setPayChannelId(substitutePayConfigDTO.getId());
                        merchantCashOut.setReturnMsg(failReason);
                        merchantCashOut.setPayChannelCode(substitutePayConfigDTO.getChannelCode());
                        merchantCashOut.setChannelOrderNo(channelResResult.getString("channelOrderNo"));
                        merchantCashOutService.updateMerchantCashOut(merchantCashOut);
                    }else if (MerchantPayOrderStatusEnum.PAY_SUCCESS.getStatus().equals(status)){
                        merchantCashOut.setTradeStatus((short) 3);
                        merchantCashOut.setOperatorName(operatorName);
                        merchantCashOut.setOperatorTime(new Date());
                        merchantCashOut.setPayChannelId(substitutePayConfigDTO.getId());
                        merchantCashOut.setPayChannelCode(substitutePayConfigDTO.getChannelCode());
                        merchantCashOut.setReturnMsg("--");
                        merchantCashOut.setChannelOrderNo(channelResResult.getString("channelOrderNo"));
                        merchantCashOutService.updateMerchantCashOut(merchantCashOut);

                        boolean lock = false;
                        String lockName = System.getenv("XY_GAME_PAY_LOCK_FLAG").concat(merchantCashOut.getTradeNumber()).concat("agentPay");
                        try {
                            if (lock = distributedLock.getLock(lockName)) {
                                if (merchantCashOut.getIsAtuoSettle() == 0) {  //结算
                                    MerchantAccountOptions merchantAccountOptions = new MerchantAccountOptions();
                                    merchantAccountOptions.setOptionType("结算成功");
                                    merchantAccountOptions.setFreezing(merchantCashOut.getAmount().negate());
                                    merchantAccountOptions.setMerchantId(merchantCashOut.getMerchantId());
                                    merchantAccountService.updateMerchantAccount(merchantAccountOptions);

                                    MerchantSettleDTO merchantSettleDTO = merchantSettleService.getMerchantSettleBySettleOrderNo(merchantCashOut.getSettleOrderOn());
                                    Integer settleStatus = Integer.valueOf(2);
                                    //已结算总金额
                                    BigDecimal settledAmt = merchantSettleDTO.getSettledAmt()==null?BigDecimal.ZERO:merchantSettleDTO.getSettledAmt();
                                    if (settledAmt.compareTo(merchantCashOut.getAmount())==0){
                                        settleStatus = Integer.valueOf(1);
                                    }
                                    merchantSettleService.updateSettleAmtAndSettleStatusBySettleOrderNo(merchantCashOut.getSettleOrderOn(),BigDecimal.ZERO, settleStatus);
                                } else if (merchantCashOut.getIsAtuoSettle() ==2) { // 实时结算申请
                                    MerchantAccountOptions merchantAccountOptions = new MerchantAccountOptions();
                                    merchantAccountOptions.setOptionType("实时结算成功");
                                    merchantAccountOptions.setFreezing(merchantCashOut.getAmount().negate());
                                    merchantAccountOptions.setMerchantId(merchantCashOut.getMerchantId());
                                    merchantAccountService.updateMerchantAccount(merchantAccountOptions);
                                }else{ //GM可提现金额提现
                                    MerchantAccountOptions merchantAccountOptions = new MerchantAccountOptions();
                                    merchantAccountOptions.setOptionType("GM提现成功");
                                    merchantAccountOptions.setCashWithdrawalIng(merchantCashOut.getAmount().negate());
                                    merchantAccountOptions.setMerchantId(merchantCashOut.getMerchantId());
                                    merchantAccountService.updateMerchantAccount(merchantAccountOptions);
                                }
                            }
                        } catch (GetLockFailedException e) {
                            LogPortal.error("{} >>> {} 获取lock失败", e, traceId, lockName);
                        } catch (Exception e) {
                            LogPortal.error("{} >>> {} 任务执行出错 ", e, traceId, lockName);
                        } finally {
                            if (lock) {
                                LogPortal.info(traceId + " >>> " + lockName + " finished.");
                                try {
                                    distributedLock.releaseLock(lockName);
                                } catch (ReleaseLockFailedException e) {
                                    LogPortal.error("{} >>> [DISTRIBUTED_LOCK_RELEASE_FAILED_ZK] 分布式锁释放失败,锁名称为:{}", traceId, lockName);
                                    LogPortal.error("{} >>> {} 释放失败", e, traceId, lockName);
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    LogPortal.error("{} 商户号:{} 发起代付，调用通道 发生{}异常", e, traceId, merchantCashOut.getMerchantId(), e.getClass().getName());
                    commonResult.setCode(-1);
                    commonResult.setMsg("代付提交失败，请联系技术支持，错误码:" + traceId);
                }
            } else {
                commonResult.setCode(-1);
                commonResult.setMsg(failMsg);
            }
        } else {
            commonResult.setCode(-1);
            commonResult.setMsg("订单已结算或拒绝！");
        }
        return commonResult;
    }
}
